package com.atguigui.leetcode;

import java.util.*;

/**
 * Java：O(1) 时间插入、删除和获取随机元素
 *
 * Project: leetcode
 * Package: com.atguigui.leetcode
 * Version: 1.0
 * <p>
 * Created by  wangjiaxin  on 2022/4/13 22:40
 */
/*
实现RandomizedSet 类：

RandomizedSet() 初始化 RandomizedSet 对象
bool insert(int val) 当元素 val 不存在时，向集合中插入该项，并返回 true ；否则，返回 false 。
bool remove(int val) 当元素 val 存在时，从集合中移除该项，并返回 true ；否则，返回 false 。
int getRandom() 随机返回现有集合中的一项（测试用例保证调用此方法时集合中至少存在一个元素）。每个元素应该有 相同的概率 被返回。
你必须实现类的所有函数，并满足每个函数的 平均 时间复杂度为 O(1) 。

示例：

输入
["RandomizedSet", "insert", "remove", "insert", "getRandom", "remove", "insert", "getRandom"]
[[], [1], [2], [2], [], [1], [2], []]
输出
[null, true, false, true, 2, true, false, 2]

解释
RandomizedSet randomizedSet = new RandomizedSet();
randomizedSet.insert(1); // 向集合中插入 1 。返回 true 表示 1 被成功地插入。
randomizedSet.remove(2); // 返回 false ，表示集合中不存在 2 。
randomizedSet.insert(2); // 向集合中插入 2 。返回 true 。集合现在包含 [1,2] 。
randomizedSet.getRandom(); // getRandom 应随机返回 1 或 2 。
randomizedSet.remove(1); // 从集合中移除 1 ，返回 true 。集合现在包含 [2] 。
randomizedSet.insert(2); // 2 已在集合中，所以返回 false 。
randomizedSet.getRandom(); // 由于 2 是集合中唯一的数字，getRandom 总是返回 2 。
提示：

-231 <= val <= 231 - 1
最多调用 insert、remove 和 getRandom 函数 2 * 105 次
在调用 getRandom 方法时，数据结构中 至少存在一个 元素。
Related Topics
设计
数组
哈希表
数学
随机化
 */
public class P380InsertDeleteGetrandomO1{
    public static void main(String[] args) {
//        Solution solution = new P380InsertDeleteGetrandomO1().new Solution();
        // TO TEST


         RandomizedSet obj = new P380InsertDeleteGetrandomO1().new RandomizedSet();
         System.out.println(obj.insert(1));
         System.out.println(obj.remove(2));
         System.out.println(obj.insert(2));
         System.out.println(obj.getRandom());
         System.out.println(obj.remove(1));
         System.out.println(obj.insert(2));
         System.out.println(obj.getRandom());








    }



    //leetcode submit region begin(Prohibit modification and deletion)
    class RandomizedSet {

        private List<Integer> nums;
        private Map<Integer, Integer> indices;


        public RandomizedSet() {
            this.nums = new ArrayList<>();
            this.indices = new HashMap<>();
        }

        /**
         * 插入数据时，首先判断hash中是否存在，存在返回false。不存在在List中插入数字并把位置存在Map中。
         *
         * @param val
         * @return
         */
        public boolean insert(int val) {

            //判断Map中是否存在
            if (indices.containsKey(val)){
                return false;
            }

            nums.add(val);
            indices.put(val, nums.size() - 1);

            return true;
        }

        /**
         * 删除数据时，首先判断map中是否存在，不存在返回false。存在拿到value后把list最后一个数字替换到删除数，并删除list中最后一个元素，更新map中移动后的数据
         *
         * @param val
         * @return
         */
        public boolean remove(int val) {

            //map中不包含要删除的key则直接返回false
            if (!indices.containsKey(val)){
                return false;
            }

            //查找出map中对应的index
            Integer index = indices.get(val);

            //得到list中last的value
            Integer lastValue = nums.get(nums.size() - 1);
            //替换数据
            nums.set(index, lastValue);
            //删除最后一个数据
            nums.remove(nums.size() - 1);

            //更新提花的index
            indices.put(lastValue, index);

            //在map中删除key
            indices.remove(val);


            return true;
        }

        /**
         * 随机获取一位
         *
         * @return
         */
        public int getRandom() {
            Random random = new Random();
            int randomIndex = random.nextInt(nums.size());
            return nums.get(randomIndex);
        }
    }

/**
 * Your RandomizedSet object will be instantiated and called as such:
 * RandomizedSet obj = new RandomizedSet();
 * boolean param_1 = obj.insert(val);
 * boolean param_2 = obj.remove(val);
 * int param_3 = obj.getRandom();
 */
//leetcode submit region end(Prohibit modification and deletion)

}
